/*
Copyright 2020 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
	"strings"

	"github.com/spf13/pflag"
	cliflag "k8s.io/component-base/cli/flag"

	cmdutil "github.com/jetstack/cert-manager/cmd/util"
)

const (
	// Default port on which /validate, /mutate, /convert endpoints will be served
	defaultListeningPort = 6443
	// Default health check port
	defaultHealthPort = 6080
)

type WebhookOptions struct {
	ListenPort  int
	HealthzPort int

	// Path to TLS certificate and private key on disk.
	// Both must be specified if either is.
	// May not be specified if DynamicServingCASecretNamespace and
	// DynamicServingCASecretName are set.
	TLSCertFile string
	TLSKeyFile  string

	// Namespace and name of the Secret resource containing the TLS certificate
	// used as a CA to sign dynamic serving certificates.
	// Both must be specified if either is.
	// May not be specified if TLSCertFile and TLSKeyFile are set.
	DynamicServingCASecretNamespace string
	DynamicServingCASecretName      string
	// List of DNSNames that must be present on serving certificates.
	DynamicServingDNSNames []string

	// Optional path to the kubeconfig used to connect to the apiserver when
	// using the 'dynamic serving' certificate sources.
	// If not specified, in cluster config will be used.
	Kubeconfig    string
	APIServerHost string

	// TLSCipherSuites is the list of allowed cipher suites for the server.
	// Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants).
	TLSCipherSuites []string

	// MinTLSVersion is the minimum TLS version supported.
	// Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants).
	MinTLSVersion string

	// EnablePprof determines whether pprof is enabled.
	EnablePprof bool

	// Address on which /debug/pprof endpoint will be served if enabled. Default is
	// localhost:6060.
	PprofAddress string
}

func (o *WebhookOptions) AddFlags(fs *pflag.FlagSet) {
	// TODO: rename secure-port to listen-port
	fs.IntVar(&o.ListenPort, "secure-port", defaultListeningPort, "port number to listen on for secure TLS connections")
	fs.IntVar(&o.HealthzPort, "healthz-port", defaultHealthPort, "port number to listen on for insecure healthz connections")
	fs.StringVar(&o.TLSCertFile, "tls-cert-file", "", "path to the file containing the TLS certificate to serve with")
	fs.StringVar(&o.TLSKeyFile, "tls-private-key-file", "", "path to the file containing the TLS private key to serve with")
	fs.StringVar(&o.DynamicServingCASecretNamespace, "dynamic-serving-ca-secret-namespace", "", "namespace of the secret used to store the CA that signs serving certificates")
	fs.StringVar(&o.DynamicServingCASecretName, "dynamic-serving-ca-secret-name", "", "name of the secret used to store the CA that signs serving certificates certificates")
	fs.StringSliceVar(&o.DynamicServingDNSNames, "dynamic-serving-dns-names", []string{""}, "DNS names that should be present on certificates generated by the dynamic serving CA")
	fs.StringVar(&o.Kubeconfig, "kubeconfig", "", "optional path to the kubeconfig used to connect to the apiserver. If not specified, in-cluster-config will be used")
	fs.StringVar(&o.APIServerHost, "api-server-host", "", ""+
		"Optional apiserver host address to connect to. If not specified, autoconfiguration "+
		"will be attempted.")
	fs.BoolVar(&o.EnablePprof, "enable-profiling", cmdutil.DefaultEnableProfiling, ""+
		"Enable profiling for controller.")
	fs.StringVar(&o.PprofAddress, "profiler-address", cmdutil.DefaultProfilerAddr,
		"Address of the Go profiler (pprof). This should never be exposed on a public interface. If this flag is not set, the profiler is not run.")
	tlsCipherPossibleValues := cliflag.TLSCipherPossibleValues()
	fs.StringSliceVar(&o.TLSCipherSuites, "tls-cipher-suites", o.TLSCipherSuites,
		"Comma-separated list of cipher suites for the server. "+
			"If omitted, the default Go cipher suites will be use.  "+
			"Possible values: "+strings.Join(tlsCipherPossibleValues, ","))
	tlsPossibleVersions := cliflag.TLSPossibleVersions()
	fs.StringVar(&o.MinTLSVersion, "tls-min-version", o.MinTLSVersion,
		"Minimum TLS version supported. "+
			"Possible values: "+strings.Join(tlsPossibleVersions, ", "))

}

func FileTLSSourceEnabled(o WebhookOptions) bool {
	if o.TLSCertFile != "" || o.TLSKeyFile != "" {
		return true
	}
	return false
}

func DynamicTLSSourceEnabled(o WebhookOptions) bool {
	if o.DynamicServingCASecretNamespace != "" || o.DynamicServingCASecretName != "" {
		return true
	}
	return false
}
